/*
	jGrouse framework
	Copyright 2007 by Denis Riabtchik 
	All rights reserved.
	
	Licensed under modified BSD license. See license.txt for details
*/

/**
	@module jgrouse.util.Catalog
	@requires module-jgrouse.util.Maps
	@requires module-jgrouse.util.Sets
*/

jgrouse.module(
{
	name : 'jgrouse.util.Catalog',
	requires : ['jgrouse.util.Maps', 'jgrouse.util.Sets'],
	imports : ['jgrouse.util.ObjectMap', 'jgrouse.util.ObjectSet'],
	body : function(embed)
	{
		eval(embed);
		
		/**
			Catalog - a map where each element (box) contains an array
			@class jgrouse.util.Catalog
			@extends jgrouse.BaseObject
		*/
		jgrouse.define('jgrouse.util.Catalog', 'jgrouse.BaseObject', function(salt)
		{
			eval(salt);
			
			return {
				/**
					@constructor initialize
					@param {function(key, item)} boxComparator - function that compares box's key to given 
					item and returns true if they are the same
				*/
				initialize : function(boxComparator)
				{
					_super(this, 'initialize');
					this._boxes = new ObjectMap(boxComparator);
				},
				
				_createSet : function()
				{
					return new ObjectSet(jgrouse.objectComparator);
				},
				
				/**
					Add item to catalog. New box would be created when necessary.
					@function add
					@param {Object} key - key for map
					@param {Object} value - value to be added to catalog
				*/
				add : function(key, value)
				{
					var box = this._boxes.get(key);
					if (!box)
					{
						box = this._createSet();
						this._boxes.put(key, box);
					}
					box.put(value);
				},
				
				/**
					Remove item from catalog. Note - empty boxes are not removed
					@function remove
					@param {Object} key - key for map
					@param {Object} value - value to be removed
				*/
				remove : function(key, value)
				{
					var box = this._boxes.get(key);
					if (box)
					{
						box.remove(value);
					}
				},
				
				/**
					Remove the box matching the key
					@function ?
					@param {Object} key - the key for the box
				*/
				removeBox : function(key)
				{
					this._boxes.remove(key);
				},
				
				/**
					Call a callback function for each item in catalog's box.
					@function forEachInBox
					@param {Object} key - key for map, identifies a box
					@param {objectIteratorCallback} iter - callback to be called. 
				*/
				forEachInBox : function(key, iter)
				{
					var box = this._boxes.get(key);
					if (box)
					{
						box.forEach(function(value)
						{
							iter(value, key);
						});
					}
				},
				
				/**
					Call a callback function for each item in catalog, for each boxes.
					@function forEach
					@param {objectIteratorCallback} iter - function to be called for each item in catalog 
				*/
				forEach : function(iter)
				{
					this._boxes.forEach(function(box, key)
					{
						box.forEach(function(value)
						{
							iter(value, key);
						});
					});
				},
				
				/**
					Call a callback function for each box
					@function forEachBox
					@param {objectIteratorCallback} iter - callback function
					@param {boolean} backwards - if iterations should start from the end
				*/
				forEachBox : function(iter, backwards)
				{
					this._boxes.forEach(iter, backwards);
				},
				
				/**
					Remove all entries for given value
					@function removeAll
					@param {Object} value - value to be removed
				*/
				removeAll : function(value)
				{
					this._boxes.forEach(function(box, key)
					{
						box.remove(value);
					});
				},
				
				/**
					Clear catalog
					@function clear
				*/
				clear : function()
				{
					this._boxes.forEach(function(box, key)
					{
						box.clear();
					});
					this._boxes.clear();
				},
				
				/**
					Returns an array containing keys for all boxes
					@function {Object[]} keys
				*/
				keys : function()
				{
					return this._boxes.keys();
				}
			};
		});
	}
});